home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Cappuccino / Source / CappuccinoContent.cpp < prev    next >
Encoding:
Text File  |  1995-12-11  |  49.6 KB  |  1,667 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CappuccinoContent.cpp
  3.  
  4.     Contains:    Class to encapsulate the content of the Cappuccino part.
  5.     
  6.     Written by:    Troy Gaul
  7.     
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // -- Compiler/Preprocessor Switches --
  12.  
  13. #ifndef _COMPILERDEFS_
  14. #include "CompDefs.h"
  15. #endif
  16.  
  17. // -- OpenDoc Utilities --
  18.  
  19. #ifndef _EXCEPT_
  20. // Exceptions define several important macros (eg. CHECKENV)
  21. // which are used in the SOM method dispatch glue. If Except.h
  22. // is not included early enough, exceptions may not be thrown
  23. // correctly when returning from a SOM method with the "ev" parameter set.
  24. #include <Except.h>
  25. #endif
  26.  
  27. // -- Cappuccino Includes --
  28.  
  29. #ifndef _CAPPUCCINOCONTENT_
  30. #include "CappuccinoContent.h"
  31. #endif
  32.  
  33. #ifndef _CAPPUCCINO_
  34. #include "Cappuccino.h"
  35. #endif
  36.  
  37. #ifndef _CAPPUCCINOACTION_
  38. #include "CappuccinoAction.h"
  39. #endif
  40.  
  41. #ifndef _CAPPUCCINODEF_
  42. #include "CappuccinoDef.h"
  43. #endif
  44.  
  45. #ifndef _CAPPUCCINOGLOBALS_
  46. #include "CappuccinoGlobals.h"
  47. #endif
  48.  
  49. #ifndef _CAPPUCCINOPROMISE_
  50. #include "CappuccinoPromise.h"
  51. #endif
  52.  
  53. #ifndef _CAPPUCCINOUTILS_
  54. #include "CappuccinoUtils.h"
  55. #endif
  56.  
  57. #ifndef _TEMPFOCUS_
  58. #include "TempFocus.h"
  59. #endif
  60.  
  61. // -- OpenDoc Includes --
  62.  
  63. #ifndef SOM_ODCanvas_xh
  64. #include <Canvas.xh>
  65. #endif
  66.  
  67. #ifndef SOM_ODFacet_xh
  68. #include <Facet.xh>
  69. #endif
  70.  
  71. #ifndef SOM_ODFrame_xh
  72. #include <Frame.xh>
  73. #endif
  74.  
  75. #ifndef SOM_ODStorageUnit_xh
  76. #include <StorageU.xh>
  77. #endif
  78.  
  79. #ifndef SOM_ODTranslation_xh
  80. #include <Translt.xh>
  81. #endif
  82.  
  83. #ifndef SOM_ODContainer_xh
  84. #include <ODCtr.xh>
  85. #endif
  86.  
  87. #ifndef SOM_ODSession_xh
  88. #include <ODSessn.xh>
  89. #endif
  90.  
  91. #ifndef SOM_ODShape_xh
  92. #include <Shape.xh>
  93. #endif
  94.  
  95. #ifndef SOM_Module_OpenDoc_StdProps_defined
  96. #include <StdProps.xh>
  97. #endif
  98.  
  99. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  100. #include <StdTypes.xh>
  101. #endif
  102.  
  103. // -- Macintosh Includes --
  104.  
  105. #ifndef __TEXTUTILS__
  106. #include <TextUtils.h>
  107. #endif
  108.  
  109. #ifndef __TOOLUTILS__
  110. #include <ToolUtils.h>
  111. #endif
  112.  
  113. // -- OpenDoc Utilites --
  114.  
  115. #ifndef _DLOGUTIL_
  116. #include "DlogUtil.h"
  117. #endif
  118.  
  119. #ifndef _ISOSTR_
  120. #include "ISOStr.h"
  121. #endif
  122.  
  123. #ifndef _ITEXT_
  124. #include "IText.h"
  125. #endif
  126.  
  127. #ifndef _ODDEBUG_
  128. #include "ODDebug.h"
  129. #endif
  130.  
  131. #ifndef _ODUTILS_
  132. #include "ODUtils.h"
  133. #endif
  134.  
  135. #ifndef _PASCLSTR_
  136. #include "PasclStr.h"
  137. #endif
  138.  
  139. #ifndef _STDTYPIO_
  140. #include "StdTypIO.h"
  141. #endif
  142.  
  143. #ifndef _STORUTIL_
  144. #include "StorUtil.h"
  145. #endif
  146.  
  147. #ifndef _TEMPITER_
  148. #include "TempIter.h"
  149. #endif
  150.  
  151. #ifndef _TEMPOBJ_
  152. #include "TempObj.h"
  153. #endif
  154.  
  155. //==============================================================================
  156. #pragma mark    • Utility functions •
  157. //==============================================================================
  158.  
  159. //------------------------------------------------------------------------------
  160. // ClipString
  161. //------------------------------------------------------------------------------
  162.  
  163. static void ClipString( StringPtr string )
  164. {
  165.     if ( string[0] == 255 )
  166.         ClipStringToBytes(string, string[0], gGlobals->fEditorsScript);
  167. }
  168.  
  169. //------------------------------------------------------------------------------
  170. // ExactlyEqualStrings
  171. //------------------------------------------------------------------------------
  172.  
  173. static ODBoolean ExactlyEqualStrings( StringPtr a, StringPtr b )
  174. {
  175.     if (a[0] != b[0])
  176.         return kODFalse;
  177.     
  178.     for (int i = 1; i <= a[0]; i++)
  179.     {
  180.         if ( a[i] != b[i] )
  181.             return kODFalse;
  182.     }
  183.     
  184.     return kODTrue;
  185. }
  186.  
  187. //------------------------------------------------------------------------------
  188. // GetFlavorFromSU
  189. //------------------------------------------------------------------------------
  190.  
  191. static void GetFlavorFromSU( Environment*        ev,
  192.                              ODStorageUnit*        su,
  193.                              HFSFlavor*            flavor )
  194. {
  195.     const ODSize kMinHFSFlavorSize = 2 * sizeof(OSType) + sizeof(unsigned short) 
  196.                                      + sizeof(short) + sizeof(long) + sizeof(char);
  197.     
  198.     if ( ODSUExistsThenFocus(ev, su, kODPropContents, 
  199.                              gGlobals->fAppleHFSFlavorValueType) )
  200.     {    
  201.         ODSize size = su->GetSize(ev);
  202.     
  203.         if ( size < kMinHFSFlavorSize || size > sizeof(HFSFlavor) )
  204.             THROW_M(kODErrInvalidValueType, "HFSFlavor value wasn't of appropriate size to be valid.");
  205.     
  206.         StorageUnitGetValue(su, ev, size, flavor);
  207.     }
  208.     else
  209.     {
  210.         THROW(kODErrInvalidValueType);
  211.     }
  212. }
  213.  
  214. //------------------------------------------------------------------------------
  215. // GetCappuccinoKindProp
  216. //------------------------------------------------------------------------------
  217.  
  218. static StringPtr GetCappuccinoKindProp( Environment*        ev, 
  219.                                         ODStorageUnit*        su, 
  220.                                         ODPropertyName        prop, 
  221.                                         ODValueType            val )
  222. {
  223.     StringPtr string = kODNULL;
  224.     
  225.     if ( ODSUExistsThenFocus(ev, su, prop, val) )
  226.     {
  227.         ODULong size = su->GetSize(ev);
  228.         
  229.         if ( size == 0 )
  230.         {
  231.             string = (StringPtr) ODNewPtrClear(1);
  232.         }
  233.         else
  234.         {
  235.             su->SetOffset(ev, 0);
  236.             
  237.             if ( size > 255 )
  238.                 size = 255;
  239.                 
  240.             string = (StringPtr) ODNewPtr(size);
  241.             string[0] = size;
  242.             
  243.             TRY
  244.                 StorageUnitGetValue(su, ev, size, string);
  245.             CATCH_ALL
  246.                 ODDisposePtr(string);
  247.                 RERAISE;
  248.             ENDTRY
  249.             
  250.             // Clip the string after having read it in case it was longer than 255
  251.             // characters.  This is to attempt to adjust it for double-byte scripts,
  252.             // but might not fully work correctly.
  253.             ClipString(string);
  254.         }
  255.     }
  256.  
  257.     return string;
  258. }
  259.  
  260. //------------------------------------------------------------------------------
  261. // SetCappuccinoKindProp
  262. //------------------------------------------------------------------------------
  263.  
  264. static void SetCappuccinoKindProp( Environment*            ev, 
  265.                                    ODStorageUnit*        su, 
  266.                                    ODPropertyName        prop, 
  267.                                    ODValueType            val,
  268.                                    StringPtr            string )
  269. {
  270.     ODSUForceFocus(ev, su, prop, val);
  271.     
  272.     ODULong oldsize = su->GetSize(ev);
  273.     ODULong newsize = string[0] + 1;
  274.     
  275.     StorageUnitSetValue(su, ev, newsize, string);    
  276.     
  277.     if ( oldsize > newsize )
  278.         su->DeleteValue(ev, oldsize - newsize);
  279. }
  280.  
  281. //==============================================================================
  282. // CCappuccinoContent
  283. //==============================================================================
  284. #pragma mark    -
  285.  
  286. //------------------------------------------------------------------------------
  287. // Method:        Constructor
  288. // Origin:        CCappuccinoContent
  289. //------------------------------------------------------------------------------
  290.  
  291. CCappuccinoContent::CCappuccinoContent(Cappuccino* part)
  292. {
  293.     fPart    = part;
  294.     fString    = kODNULL;
  295. }
  296.     
  297. //------------------------------------------------------------------------------
  298. // Method:        Destructor
  299. // Origin:        CCappuccinoContent
  300. //
  301. // Notes:        It must be safe to call this routine even if none of the Init
  302. //                methods have been called (or if the Init methods fail).
  303. //------------------------------------------------------------------------------
  304.  
  305. CCappuccinoContent::~CCappuccinoContent()
  306. {
  307.     ODDisposePtr(fString);
  308. }
  309.  
  310. //==============================================================================
  311. #pragma mark    • I/O •
  312. //==============================================================================
  313.  
  314. //------------------------------------------------------------------------------
  315. // Method:        InitCappuccinoContent ()
  316. // Origin:        CCappuccinoContent
  317. //------------------------------------------------------------------------------
  318.  
  319. void CCappuccinoContent::InitCappuccinoContent( Environment*    ev )
  320. {
  321.     fString = (StringPtr) ODNewPtrClear(1);
  322. }
  323.  
  324. //------------------------------------------------------------------------------
  325. // Method:        InitCappuccinoContent (StringPtr)
  326. // Origin:        CCappuccinoContent
  327. //------------------------------------------------------------------------------
  328.  
  329. void CCappuccinoContent::InitCappuccinoContent( Environment*    ev, 
  330.                                                 StringPtr        string )
  331. {
  332.     fString = (StringPtr) ODNewPtr(string[0] + 1);
  333.     ODBlockMove(string, fString, string[0] + 1);
  334. }
  335.  
  336. //------------------------------------------------------------------------------
  337. // Method:        InitCappuccinoContent (ODStorageUnit)
  338. // Origin:        CCappuccinoContent
  339. //------------------------------------------------------------------------------
  340.  
  341. void CCappuccinoContent::InitCappuccinoContent( Environment*        ev, 
  342.                                                 ODStorageUnit*        su )
  343. {
  344.     ODValueType kindToUse = this->GetKindToInternalize(ev, su);
  345.  
  346.     if ( ODISOStrEqual(kindToUse, kCappuccinoKind) )
  347.     {
  348.         this->InternalizeCappuccinoKind(ev, su);
  349.     }
  350. #ifndef qSingleKindSupported
  351.     else if ( ODISOStrEqual(kindToUse, gGlobals->fTextDataValueType) )
  352.     {
  353.         this->InternalizeTextData(ev, su);
  354.     }
  355.     else if ( HasValidFile(ev, su) )
  356.     {
  357.         this->InternalizeTextFile(ev, su);
  358.     }
  359. #endif
  360.     else
  361.     {
  362.         this->InternalizeTranslatedData(ev, su);
  363.     }
  364. }
  365.  
  366. //------------------------------------------------------------------------------
  367. // Method:        InitByTranslating
  368. // Origin:        CCappuccinoContent
  369. //
  370. // Description:    This method is called when handling the Paste As dialog box in
  371. //                order to take data from and to given formats and create a new
  372. //                content object that fits that translation.  It is also called
  373. //                by the content object to do the actual translation of data.
  374. //------------------------------------------------------------------------------
  375.  
  376. void CCappuccinoContent::InitByTranslating( Environment*        ev,
  377.                                             ODStorageUnit*        su,
  378.                                             ODValueType            from,
  379.                                             ODValueType            to )
  380. {
  381.     WASSERT(CCappuccinoContent::IsKindSupported(ev, to));
  382.     
  383.     ODSession* session = ODGetSession(ev, su);
  384.     
  385.     // Create the "from" storage unit view.
  386.     su->Focus(ev, kODPropContents, kODPosUndefined, from, 0, kODPosUndefined);
  387.     TempODStorageUnitView fromView = su->CreateView(ev);
  388.     
  389.     // Create the "to" storage unit view.
  390.     TempODHandle        cntrHandle = kODNULL;
  391.     TempODContainer     container  = kODNULL;
  392.     TempODDocument      document   = kODNULL;
  393.     TempODDraft         toDraft    = kODNULL;
  394.     
  395.     ODDraft* partDraft = ODGetDraft(ev, fPart->GetODPart());
  396.     
  397.     if ( partDraft->GetPermissions(ev) >= kODDPSharedWrite )
  398.     {
  399.         partDraft->Acquire(ev);
  400.         toDraft = partDraft;
  401.     }
  402.     else
  403.     {
  404.         // In the case where we don't have write access to our draft, we
  405.         // create a new in-memory container to translate the data into.
  406.         // Creating an in-memory container is a potentially expensive
  407.         // operation, so it might be better to use an in-memory translation
  408.         // via Translate(), but our Content object is only set up to read data
  409.         // from storage units, so this doesn't work for us right now.
  410.     
  411.         cntrHandle = ODNewHandle(0);
  412.         container  = CreateMemoryContainer(ev, session, cntrHandle,
  413.                                            kODDefaultMemoryContainer);
  414.         document   = container->AcquireDocument(ev, kODDefaultDocument);
  415.         toDraft    = document->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  416.     }
  417.  
  418.     TempODStorageUnit toSU = toDraft->CreateStorageUnit(ev);
  419.     
  420.     TRY
  421.         ODSUForceFocus(ev, toSU, kODPropContents, to);        
  422.         TempODStorageUnitView toView = toSU->CreateView(ev);
  423.         
  424.         // Get the translation object and perform the translation.
  425.         ODTranslation* translation = session->GetTranslation(ev);
  426.         ODTranslateResult translateResult = translation->TranslateView(ev, fromView, toView);
  427.         
  428.         // Call InitCappuccinoContent (recursively) to read from this.  Note that
  429.         // this should not cause this routine to get called again, as there is now
  430.         // a value type that the content supports, so translation will not be needed
  431.         // in this second call.  Also, if for some reason TranslateView returns 
  432.         // kODCannotTranslate, we just punt and call InitCappuccinoContent to set us
  433.         // up to be empty.
  434.         if ( translateResult != kODCannotTranslate )
  435.             this->InitCappuccinoContent(ev, toSU);
  436.         else
  437.             this->InitCappuccinoContent(ev);
  438.     CATCH_ALL
  439.         // Remove our temporary storage unit.
  440.         toSU->Focus(ev, kODNULL, kODPosAll, kODTypeAll, 0, kODPosUndefined);
  441.         toSU->Remove(ev);
  442.         RERAISE;
  443.     ENDTRY
  444.     
  445.     // Remove our temporary storage unit.
  446.     toSU->Focus(ev, kODNULL, kODPosAll, kODTypeAll, 0, kODPosUndefined);
  447.     toSU->Remove(ev);
  448.  
  449. /*    if ( pasteAsResult.translateKind != kODNULL )
  450.     {
  451.         // Translation was requested from translateKind to selectedKind
  452.         
  453.         // Create the from storage unit view.
  454.         contentSU->Focus(ev, kODPropContents, kODPosUndefined, pasteAsResult.translateKind, 
  455.                          0, kODPosUndefined);
  456.         TempODStorageUnitView fromView = contentSU->CreateView(ev);
  457.         
  458.         // If there's a content property at the destination, we need to remove
  459.         // it because otherwise TranslateView might leave it with stale data.
  460.         if ( ODSUExistsThenFocus(ev, storageUnit, kODPropContents, kODNULL) )
  461.             storageUnit->Remove(ev);
  462.         
  463.         // Add selectedKind and create the to storage unit view
  464.         ODSUForceFocus(ev, storageUnit, kODPropContents, pasteAsResult.selectedKind);        
  465.         TempODStorageUnitView toView = storageUnit->CreateView(ev);
  466.         
  467.         // Get the translation object and perform the translation.
  468.         ODTranslation* translation = fSession->GetTranslation(ev);
  469.         ODTranslateResult translateResult = translation->TranslateView(ev, fromView, toView);
  470.         
  471.         // Check for sucessful translation.
  472.         if ( translateResult != kODCannotTranslate )
  473.         {
  474.             // Create an action to paste the new content.
  475.             content->InitCappuccinoContent(ev, storageUnit);
  476.         }
  477.     }
  478.     else
  479.     {
  480.         content->InitCappuccinoContent(ev, contentSU);
  481.     }
  482.     
  483.     if ( content != kODNULL )
  484.     {
  485.         // Create an action to paste the new content.
  486.         CPasteAction* action = new CPasteAction(this, content);
  487.         action->Perform(ev);
  488.     }
  489. */
  490. }
  491.  
  492. //------------------------------------------------------------------------------
  493. // Method:        Prepare
  494. // Origin:        CCappuccinoContent
  495. //
  496. // Description:    This method will clean out the content property of the given
  497. //                storage unit so that there are no extraneous kinds that we
  498. //                don't support.  Also, it must make sure that the ones that are
  499. //                left are in the correct order.  This is actually a pretty
  500. //                tricky thing to do for the general case, so this routine is
  501. //                written to work directly on the supported preferred kinds.
  502. //------------------------------------------------------------------------------
  503.  
  504. void CCappuccinoContent::Prepare( Environment*        ev, 
  505.                                   ODStorageUnit*    su,
  506.                                   ODValueType        preferredKind )
  507. {
  508. #ifndef qSingleKindSupported
  509.     WASSERT(preferredKind == kODNULL || this->IsKindSupported(ev, preferredKind));
  510.     
  511.     su->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  512.     ODULong numValues = su->CountValues(ev);
  513.     
  514.     ODBoolean hasReadCappuccinoKind = kODFalse;
  515.  
  516.     for ( ODULong index = numValues; index >= 1; index-- )
  517.     {
  518.         // Index from 1 to n through the values.
  519.         su->Focus(ev, kODPropContents, kODPosUndefined, 
  520.                   kODNULL, index, kODPosUndefined);
  521.                                 
  522.         // Get the ISO type name for the value. The temp object
  523.         // will automatically delete the returned value when this
  524.         // scope is exited.
  525.         TempODValueType value = su->GetType(ev);
  526.         
  527.         ODBoolean removeValue = kODTrue;
  528.         
  529.         if ( preferredKind == kODNULL || ODISOStrEqual(preferredKind, kCappuccinoKind) )
  530.         {
  531.             // We shouldn't remove the CappuccinoKind value if it's there.
  532.             // Also, we should only have one in the content property.
  533.             if ( !hasReadCappuccinoKind && ODISOStrEqual(value, kCappuccinoKind) )
  534.             {
  535.                 removeValue = kODFalse;
  536.                 hasReadCappuccinoKind = kODTrue;
  537.             }
  538.             
  539.             // The CappuccinoKind has to be included before the text kind.
  540.             // If it has been included yet, we'll have to delete the text
  541.             // kind value.
  542.             if ( hasReadCappuccinoKind && ODISOStrEqual(value, gGlobals->fTextDataValueType) )
  543.                 removeValue = kODFalse;
  544.         }
  545.         else if ( ODISOStrEqual(preferredKind, gGlobals->fTextDataValueType) )
  546.         {
  547.             if ( ODISOStrEqual(value, gGlobals->fTextDataValueType) )
  548.                 removeValue = kODFalse;
  549.         }
  550.         
  551.         if ( removeValue )
  552.             su->Remove(ev);
  553.     }
  554. #else
  555.     su->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  556.     ODULong numValues = su->CountValues(ev);
  557.  
  558.     for ( ODULong index = numValues; index >= 1; index-- )
  559.     {
  560.         // Index from 1 to n through the values.
  561.         su->Focus(ev, kODPropContents, kODPosUndefined, 
  562.                   kODNULL, index, kODPosUndefined);
  563.                                 
  564.         // Get the ISO type name for the value. The temp object
  565.         // will automatically delete the returned value when this
  566.         // scope is exited.
  567.         TempODValueType value = su->GetType(ev);
  568.         
  569.         if ( !ODISOStrEqual(value, kCappuccinoKind) )
  570.             su->Remove(ev);
  571.     }
  572. #endif
  573. }
  574.     
  575. //------------------------------------------------------------------------------
  576. // Method:        Externalize
  577. // Origin:        CCappuccinoContent
  578. //
  579. // Description:    This method will write out values based on the preferred kind
  580. //                (assuming the highest fidelity preferred kind if the 
  581. //                preferredKind value is null).  It should also write out any
  582. //                data interchange values, if possible.
  583. //------------------------------------------------------------------------------
  584.  
  585. void CCappuccinoContent::Externalize( Environment*        ev, 
  586.                                       ODStorageUnit*    su,
  587.                                       ODDraftKey        key,
  588.                                       ODValueType        preferredKind )
  589. {
  590. #ifndef qSingleKindSupported
  591.     WASSERT(preferredKind == kODNULL || 
  592.             this->IsKindSupported(ev, preferredKind));
  593.     
  594.     if ( preferredKind == kODNULL || ODISOStrEqual(preferredKind, kCappuccinoKind) )
  595.     {
  596.         this->ExternalizeCappuccinoKind(ev, su);
  597.         // Externalize a standard data interchange kind.
  598.         this->ExternalizeTextData(ev, su);
  599.     }
  600.     else if ( ODISOStrEqual(preferredKind, gGlobals->fTextDataValueType) )
  601.     {
  602.         this->ExternalizeTextData(ev, su);
  603.     }
  604. #else
  605.     this->ExternalizeCappuccinoKind(ev, su);
  606. #endif
  607. }
  608.     
  609. //------------------------------------------------------------------------------
  610. // Method:        ExternalizeOneKind
  611. // Origin:        CCappuccinoContent
  612. //------------------------------------------------------------------------------
  613.  
  614. void CCappuccinoContent::ExternalizeOneKind( Environment*        ev, 
  615.                                              ODStorageUnit*        su, 
  616.                                              ODDraftKey            key, 
  617.                                              ODValueType        kind )
  618. {
  619. #ifndef qSingleKindSupported
  620.     WASSERT(this->IsKindSupported(ev, kind));
  621.  
  622.     if ( ODISOStrEqual(kind, kCappuccinoKind) )
  623.         this->ExternalizeCappuccinoKind(ev, su);
  624.     else if ( ODISOStrEqual(kind, gGlobals->fTextDataValueType) )
  625.         this->ExternalizeTextData(ev, su);
  626. #else
  627.     WASSERT(ODISOStrEqual(kind, kCappuccinoKind));
  628.     this->ExternalizeCappuccinoKind(ev, su);
  629. #endif
  630. }
  631.  
  632. //==============================================================================
  633. #pragma mark    • Promises •
  634. //==============================================================================
  635.  
  636. //------------------------------------------------------------------------------
  637. // Method:        Promise
  638. // Origin:        CCappuccinoContent
  639. //
  640. // Description:    This method will write out a data interchange value to the 
  641. //                content property when it is called.  It should be called when
  642. //                externalizing data for a drag-and-drop, cut, or copy operation.
  643. //------------------------------------------------------------------------------
  644.  
  645. void CCappuccinoContent::Promise( Environment*        ev, 
  646.                                   ODStorageUnit*    su,
  647.                                   ODDraftKey        key,
  648.                                   ODBoolean            isForClipboard,
  649.                                   Cappuccino*        part )
  650. {
  651.     CCappuccinoContentPromise* nativePromise 
  652.             = new CCappuccinoContentPromise(part, this, kCappuccinoKind);
  653.     
  654. #ifndef qSingleKindSupported
  655.     CCappuccinoContentPromise* interchangePromise 
  656.             = new CCappuccinoContentPromise(part, this, gGlobals->fTextDataValueType);
  657. #endif
  658.             
  659.     nativePromise->PromiseTo(ev, su);
  660.     interchangePromise->PromiseTo(ev, su);
  661.     
  662.     // Add our promises to the appropriate promise set.
  663.     CPromiseSet* set = isForClipboard ? gGlobals->fClipboardPromises
  664.                                       : gGlobals->fDragPromises;
  665.     set->Clear(ev);
  666.     set->Add(ev, nativePromise);
  667. #ifndef qSingleKindSupported
  668.     set->Add(ev, interchangePromise);
  669. #endif
  670. }
  671.  
  672. //------------------------------------------------------------------------------
  673. // Method:        Fulfill
  674. // Origin:        CCappuccinoContent
  675. //
  676. // Description:    This method will fulfill a promise made to a storage unit by
  677. //                an instance of this content object.
  678. //------------------------------------------------------------------------------
  679.  
  680. void CCappuccinoContent::Fulfill( Environment*        ev, 
  681.                                   ODStorageUnit*    su,
  682.                                   ODValueType        valueType )
  683. {
  684.     this->ExternalizeOneKind(ev, su, kODNULLKey, valueType);
  685. }
  686.  
  687. //==============================================================================
  688. #pragma mark    • Accessors •
  689. //==============================================================================
  690.  
  691. //------------------------------------------------------------------------------
  692. // Method:        GetString
  693. // Origin:        CCappuccinoContent
  694. //------------------------------------------------------------------------------
  695.     
  696. StringPtr CCappuccinoContent::GetString()
  697. {
  698.     return fString;
  699. }
  700.     
  701. //------------------------------------------------------------------------------
  702. // Method:        IsEmpty
  703. // Origin:        CCappuccinoContent
  704. //------------------------------------------------------------------------------
  705.     
  706. ODBoolean CCappuccinoContent::IsEmpty()
  707. {
  708.     return (fString[0] == 0);
  709. }
  710.     
  711. //==============================================================================
  712. #pragma mark    • Imaging •
  713. //==============================================================================
  714.  
  715. //------------------------------------------------------------------------------
  716. // Method:        Draw
  717. // Origin:        CCappuccinoContent
  718. //------------------------------------------------------------------------------
  719.  
  720. void CCappuccinoContent::Draw( Environment*        ev,
  721.                                  ODFacet*            facet,
  722.                                  CSettings*        settings )
  723. {
  724.     SOM_Trace("Cappuccino","DrawFrameView");
  725.  
  726.     ASSERT_NOT_NULL(facet);
  727.  
  728.     // If the facet being draw is dependent to a source frame in
  729.     // another window, we need to access the source frame to determine
  730.     // what size to draw the content.
  731.  
  732.     ODFrame* frame = facet->GetFrame(ev);
  733.     CFrameInfo* frameInfo = CFrameInfo::GetFrameInfo(ev, frame);
  734.     
  735.     // Get the facet's canvas so shapes are returned in the correct
  736.     // coordinate system.
  737.     ODCanvas* biasCanvas = facet->GetCanvas(ev);
  738.  
  739.     // Calculate font height for drawing.
  740.     TempODShape frameShape = frame->AcquireFrameShape(ev, biasCanvas);
  741.     ODRgnHandle frameRgn = frameShape->GetQDRegion(ev);
  742.     Rect bounds = (**frameRgn).rgnBBox;
  743.     
  744.     PenState penState;
  745.     GetPenState(&penState);
  746.     PenNormal();
  747.             
  748.     if ( settings->GetDoesDrawFrame() )
  749.     {
  750.         FrameRect(&bounds);
  751.         
  752.         Rect eraseBounds = bounds;
  753.         InsetRect(&eraseBounds, 1, 1);
  754.         EraseRect(&eraseBounds);
  755.     }
  756.     else
  757.     {
  758.         EraseRect(&bounds);
  759.     }
  760.     
  761.     // Save off port chararcteristics so we can restore it later.
  762.     GrafPtr port = facet->GetCanvas(ev)->GetQDPort(ev);
  763.     ODUShort saveSize = port->txSize;
  764.     ODUShort saveFont = port->txFont;
  765.     Style saveFace = port->txFace;
  766.  
  767.     if ( !this->IsEmpty() )
  768.     {
  769.         // Set the font size.
  770.         TextFont(settings->GetTextFont());
  771.         TextSize(settings->GetTextSize());
  772.         TextFace(0);
  773.         
  774.         StringPtr string = this->GetString();
  775.         
  776.         Rect textBounds = bounds;
  777.         if ( settings->GetDoesDrawFrame() )
  778.             InsetRect(&textBounds, 2, 2);
  779.         
  780.         TETextBox(string + 1, string[0], &textBounds, teFlushDefault);
  781.         
  782.         // If the part is selected, fill the background with
  783.         // the highlight color.
  784.         if ( facet->GetHighlight(ev) == kODFullHighlight )
  785.         {
  786.             UInt8 mode = LMGetHiliteMode();
  787.             BitClr(&mode, pHiliteBit);
  788.             LMSetHiliteMode(mode);
  789.             InvertRect(&bounds);
  790.         }
  791.         
  792.         // Restore port chararcteristics.
  793.         port->txSize = saveSize;
  794.         port->txFont = saveFont;
  795.         port->txFace = saveFace;
  796.     }
  797.     
  798.     SetPenState(&penState);
  799. }
  800.  
  801. //==============================================================================
  802. #pragma mark    • Protected I/O methods •
  803. //==============================================================================
  804.  
  805. //------------------------------------------------------------------------------
  806. // Method:        InternalizeCappuccinoKind
  807. // Origin:        CCappuccinoContent
  808. //------------------------------------------------------------------------------
  809.  
  810. void CCappuccinoContent::InternalizeCappuccinoKind( Environment*        ev, 
  811.                                                     ODStorageUnit*        su )
  812. {
  813.     fString = GetCappuccinoKindProp(ev, su, kODPropContents, kCappuccinoKind);
  814. }
  815.  
  816. //------------------------------------------------------------------------------
  817. // Method:        InternalizeTextData
  818. // Origin:        CCappuccinoContent
  819. //------------------------------------------------------------------------------
  820. #ifndef qSingleKindSupported
  821.  
  822. void CCappuccinoContent::InternalizeTextData( Environment*        ev, 
  823.                                               ODStorageUnit*    su )
  824. {
  825.     if ( !ODSUExistsThenFocus(ev, su, kODPropContents, gGlobals->fTextDataValueType) )
  826.         THROW(kODErrInvalidValueType);
  827.     
  828.     ODULong size = su->GetSize(ev);
  829.     
  830.     // Since we only have a Pascal string, we're limited to 255 characters.
  831.     if (size > 255)
  832.         size = 255;
  833.         
  834.     fString = (StringPtr) ODNewPtrClear(size + 1);
  835.     size = StorageUnitGetValue(su, ev, size, &fString[1]);
  836.     fString[0] = size;
  837.     
  838.     // Clip the string after having read it in case it was longer than 255
  839.     // characters.  This is to attempt to adjust it for double-byte scripts,
  840.     // but might not fully work correctly.
  841.     ClipString(fString);
  842. }
  843.  
  844. #endif
  845. //------------------------------------------------------------------------------
  846. // Method:        InternalizeTextFile
  847. // Origin:        CCappuccinoContent
  848. //------------------------------------------------------------------------------
  849. #ifndef qSingleKindSupported
  850.  
  851. void CCappuccinoContent::InternalizeTextFile( Environment*        ev, 
  852.                                               ODStorageUnit*    su )
  853. {
  854.     HFSFlavor flavor;
  855.     GetFlavorFromSU(ev, su, &flavor);
  856.     
  857.     WASSERT(flavor.fileType == 'TEXT');
  858.     
  859.     ODSShort fileRefNum;
  860.     THROW_IF_ERROR(FSpOpenDF(&flavor.fileSpec, fsRdPerm, &fileRefNum));
  861.     
  862.     TRY
  863.         ODSLong size;
  864.         THROW_IF_ERROR(GetEOF(fileRefNum, &size));
  865.         
  866.         // Since we only have a Pascal string, we're limited to 255 characters,
  867.         // however, we will crop it to 254 in case we're dealing with a double-
  868.         // byte script.
  869.         if (size > 255)
  870.             size = 255;
  871.             
  872.         fString = (StringPtr) ODNewPtrClear(size + 1);
  873.         fString[0] = size;
  874.  
  875.         // If the file is empty, there's no reason to try to read it.
  876.         if ( size > 0 )
  877.         {
  878.             ODSLong bytesRead = size;
  879.             FSRead(fileRefNum, &bytesRead, &fString[1]);
  880.         }
  881.  
  882.         // Clip the string after having read it in case it was longer than 255
  883.         // characters.  This is to attempt to adjust it for double-byte scripts,
  884.         // but might not fully work correctly.
  885.         ClipString(fString);
  886.  
  887.     CATCH_ALL
  888.         FSClose(fileRefNum);
  889.         RERAISE;
  890.     ENDTRY
  891.     
  892.     FSClose(fileRefNum);
  893. }
  894.     
  895. #endif
  896. //------------------------------------------------------------------------------
  897. // Method:        InternalizeTranslatedData
  898. // Origin:        CCappuccinoContent
  899. //------------------------------------------------------------------------------
  900.  
  901. void CCappuccinoContent::InternalizeTranslatedData( Environment*        ev, 
  902.                                                     ODStorageUnit*        su )
  903. {
  904.     ODSession* session = ODGetSession(ev, su);
  905.     
  906.     // Determine the kinds that we are translating from and to.
  907.     ODValueType from = kODNULL;
  908.     ODValueType to   = kODNULL;
  909.     if ( !this->GetTranslateKinds(ev, su, &from, &to) )
  910.         THROW(kODErrInvalidValueType);
  911.     
  912.     TempODValueType fromTemp = from;
  913.     TempODValueType toTemp   = to;
  914.     
  915.     this->InitByTranslating(ev, su, from, to);
  916. }
  917.  
  918. //------------------------------------------------------------------------------
  919. // Method:        ExternalizeCappuccinoKind
  920. // Origin:        CCappuccinoContent
  921. //------------------------------------------------------------------------------
  922.  
  923. void CCappuccinoContent::ExternalizeCappuccinoKind( Environment*    ev, 
  924.                                                     ODStorageUnit*    su )
  925. {
  926.     SetCappuccinoKindProp(ev, su, kODPropContents, kCappuccinoKind, fString);
  927. }
  928.  
  929. //------------------------------------------------------------------------------
  930. // Method:        ExternalizeTextData
  931. // Origin:        CCappuccinoContent
  932. //
  933. // Description:    This method will write out a data interchange value to the 
  934. //                content property when it is called.  It should be called when
  935. //                externalizing data for a drag-and-drop, cut, or copy operation.
  936. //------------------------------------------------------------------------------
  937. #ifndef qSingleKindSupported
  938.  
  939. void CCappuccinoContent::ExternalizeTextData( Environment*        ev, 
  940.                                               ODStorageUnit*    su )
  941. {
  942.     ODSUForceFocus(ev, su, kODPropContents, gGlobals->fTextDataValueType);
  943.     ODULong oldSize = su->GetSize(ev);
  944.     
  945.     StorageUnitSetValue(su, ev, fString[0], &fString[1]);    
  946.     
  947.     if ( oldSize > fString[0] )
  948.         su->DeleteValue(ev, oldSize - fString[0]);
  949. }
  950.  
  951. #endif
  952. //==============================================================================
  953. #pragma mark    • Static utility functions •
  954. //==============================================================================
  955.  
  956. //------------------------------------------------------------------------------
  957. // Method:        IsKindSupported                                        [static]
  958. // Origin:        CCappuccinoContent
  959. //
  960. // Description:    This static method returns a boolean indicating whether the
  961. //                given kind is supported by this part.
  962. //------------------------------------------------------------------------------
  963.  
  964. ODBoolean CCappuccinoContent::IsKindSupported( Environment*     ev, 
  965.                                                ODValueType        kind )
  966. {
  967. #ifndef qSingleKindSupported
  968.     return ( ODISOStrEqual(kind, kCappuccinoKind) || 
  969.              ODISOStrEqual(kind, gGlobals->fTextDataValueType) );
  970. #else
  971.     return ( ODISOStrEqual(kind, kCappuccinoKind) );
  972. #endif
  973. }
  974.  
  975. //------------------------------------------------------------------------------
  976. // Method:        RecoverKindPtr                                        [static]
  977. // Origin:        CCappuccinoContent
  978. //
  979. // Description:    Given a pointer to an value type, we will recover a pointer to
  980. //                our constant or global version of the same type.  This is used
  981. //                to assure we have a pointer to a permanent string and not one
  982. //                that might be deleted by some other object.
  983. //------------------------------------------------------------------------------
  984.  
  985. ODValueType CCappuccinoContent::RecoverKindPtr( Environment*    ev, 
  986.                                                 ODValueType        kind )
  987. {
  988. #ifndef qSingleKindSupported
  989.     WASSERT(CCappuccinoContent::IsKindSupported(ev, kind));
  990.  
  991.     if ( ODISOStrEqual(kind, kCappuccinoKind) )
  992.         return kCappuccinoKind;
  993.     else if ( ODISOStrEqual(kind, gGlobals->fTextDataValueType) )
  994.         return gGlobals->fTextDataValueType;
  995.     else
  996.         return kODNULL;
  997. #else
  998.     return kCappuccinoKind;
  999. #endif
  1000. }
  1001.  
  1002. //------------------------------------------------------------------------------
  1003. // Function:    GetNextHighestFidelity                                [static]
  1004. //
  1005. // Description:    Returns the type token that is of the next highest fidelity
  1006. //                of the kinds we support.
  1007. //
  1008. //                If kODNULL is passed in, this returns the highest fidelity.
  1009. //
  1010. //                If the lowest fidelity is passed in, this returns kODNULL.
  1011. //------------------------------------------------------------------------------
  1012.  
  1013. ODValueType CCappuccinoContent::GetNextHighestFidelity( ODValueType currentKind )
  1014. {
  1015. #ifndef qSingleKindSupported
  1016.     ODValueType nextKind;
  1017.  
  1018.     if ( currentKind == kODNULL )
  1019.         nextKind = kCappuccinoKind;
  1020.     
  1021.     else if ( ODISOStrEqual(currentKind, kCappuccinoKind) )
  1022.         nextKind = gGlobals->fTextDataValueType;
  1023.  
  1024.     else if ( ODISOStrEqual(currentKind, gGlobals->fTextDataValueType) )
  1025.         nextKind = kODNULL;
  1026.         
  1027.     else
  1028.         // It's something we don't support, so start at the top.
  1029.         nextKind = kCappuccinoKind;
  1030.     
  1031.     return nextKind;
  1032. #else
  1033.     ODValueType nextKind;
  1034.  
  1035.     if ( currentKind == kODNULL )
  1036.         nextKind = kCappuccinoKind;
  1037.     else
  1038.         nextKind = kODNULL;
  1039.         
  1040.     return nextKind;
  1041. #endif
  1042. }
  1043.  
  1044. //------------------------------------------------------------------------------
  1045. // Function:    GetKindToInternalize                                [static]
  1046. // Origin:        CCappuccinoContent
  1047. //
  1048. // Description:    Returns a value representing the kind of data that should be
  1049. //                internalized from the given storage unit based on the kinds
  1050. //                that are supported and the preferred kind of the data.
  1051. //------------------------------------------------------------------------------
  1052.  
  1053. ODValueType CCappuccinoContent::GetKindToInternalize( Environment*        ev,
  1054.                                                       ODStorageUnit*    su )
  1055. {
  1056.     // This should represent the kind of data that should be internalized
  1057.     // from the given storage unit.
  1058.     ODValueType kindToUse = kODNULL;
  1059.  
  1060.     TempODValueType docPrefKind = ODGetISOStrProp(ev, su, kODPropPreferredKind, 
  1061.                                                    kODISOStr, kODNULL, kODNULL);
  1062.     
  1063.     // If the data has a preferred kind, see if we can use it.
  1064.     if ( docPrefKind != kODNULL 
  1065.          && CCappuccinoContent::IsKindSupported(ev, docPrefKind)
  1066.          && su->Exists(ev, kODPropContents, docPrefKind, 0) )
  1067.     {
  1068.         kindToUse = CCappuccinoContent::RecoverKindPtr(ev, docPrefKind);
  1069.     }
  1070.     
  1071.     // If there is not a part-preferred kind, we don't support it, or it 
  1072.     // wasn't found, find the first value (the one with highest fidelity) 
  1073.     // that we understand.
  1074.     if ( kindToUse == kODNULL )
  1075.         kindToUse = CCappuccinoContent::GetHighestFidelityKindSupported(ev, su);
  1076.     
  1077.     return kindToUse;
  1078. }
  1079.  
  1080. //------------------------------------------------------------------------------
  1081. // Method:        GetHighestFidelityKindSupported                        [static]
  1082. // Origin:        CCappuccinoContent
  1083. //------------------------------------------------------------------------------
  1084.  
  1085. ODValueType CCappuccinoContent::GetHighestFidelityKindSupported( Environment*    ev,
  1086.                                                                  ODStorageUnit*    su )
  1087. {
  1088. #ifndef qSingleKindSupported
  1089.     ODBoolean hasSupportedKind = kODFalse;
  1090.     
  1091.     for ( ODValueType kindToLookFor = CCappuccinoContent::GetNextHighestFidelity();
  1092.           kindToLookFor != kODNullTypeToken;
  1093.           kindToLookFor = CCappuccinoContent::GetNextHighestFidelity(kindToLookFor) )
  1094.     {
  1095.         // Note: we have to focus here (not just Exists()), or (for some reason) 
  1096.         // importing doesn't work correctly.  Instead, a translation dialog 
  1097.         // comes up and the drag (if that's what it is) is refused.
  1098.         if ( ODSUExistsThenFocus(ev, su, kODPropContents, kindToLookFor) )
  1099.         {
  1100.             return kindToLookFor;
  1101.         }
  1102.     }
  1103.     
  1104.     return kODNULL;
  1105. #else
  1106.     if ( ODSUExistsThenFocus(ev, su, kODPropContents, kCappuccinoKind) )
  1107.         return kCappuccinoKind;
  1108.     else
  1109.         return kODNULL;
  1110. #endif
  1111. }
  1112.  
  1113. //------------------------------------------------------------------------------
  1114. // Method:        HasSupportedKind                                    [static]
  1115. // Origin:        CCappuccinoContent
  1116. //------------------------------------------------------------------------------
  1117.  
  1118. ODBoolean CCappuccinoContent::HasSupportedKind( Environment*        ev,
  1119.                                                 ODStorageUnit*        su )
  1120. {
  1121.     return (CCappuccinoContent::GetHighestFidelityKindSupported(ev, su) != kODNULL);
  1122. }
  1123.  
  1124. //------------------------------------------------------------------------------
  1125. // Method:        HasValidContent                                        [static]
  1126. // Origin:        CCappuccinoContent
  1127. //
  1128. // Description:    This method is called to determine if a storage unit contains
  1129. //                any data that we understand or can translate.
  1130. //------------------------------------------------------------------------------
  1131.  
  1132. ODBoolean CCappuccinoContent::HasValidContent( Environment*        ev,
  1133.                                                ODStorageUnit*    su,
  1134.                                                ODBoolean*        requiresTranslation )
  1135. {
  1136.     SOM_Trace("CCappuccinoContent","HasValidContent");
  1137.     
  1138.     if ( requiresTranslation != kODNULL )
  1139.         *requiresTranslation = kODFalse;
  1140.     
  1141.     // Look for a type we support first to save time.                    
  1142.     if ( CCappuccinoContent::HasSupportedKind(ev, su) )
  1143.     {
  1144.         return kODTrue;
  1145.     }
  1146.     else if ( HasValidFile(ev, su) )
  1147.     {
  1148.         return kODTrue;
  1149.     }
  1150.     else if ( CCappuccinoContent::CanTranslate(ev, su) )
  1151.     {
  1152.         if ( requiresTranslation != kODNULL )
  1153.             *requiresTranslation = kODTrue;
  1154.  
  1155.         return kODTrue;
  1156.     }
  1157.     
  1158.     return kODFalse;
  1159. }
  1160.  
  1161. //------------------------------------------------------------------------------
  1162. // Method:        HasValidFile                                        [static]
  1163. // Origin:        CCappuccinoContent
  1164. //
  1165. // Description:    This method is called to determine if a storage unit contains
  1166. //                an HFSFlavor indicating a file that we can read and internalize.
  1167. //------------------------------------------------------------------------------
  1168.  
  1169. ODBoolean CCappuccinoContent::HasValidFile( Environment*        ev,
  1170.                                             ODStorageUnit*        su )
  1171. {
  1172.     ODBoolean hasValidFile = kODFalse;
  1173.     
  1174. #ifndef qSingleKindSupported
  1175.     if ( ODSUExistsThenFocus(ev, su, kODPropContents, 
  1176.                              gGlobals->fAppleHFSFlavorValueType) )
  1177.     {
  1178.         HFSFlavor flavor;
  1179.         GetFlavorFromSU(ev, su, &flavor);
  1180.         
  1181.         // We understand a plain TEXT file for compatability with other apps.
  1182.         // Note: This must be the last value that is checked for because it will
  1183.         // exist if an OpenDoc file with one of the other values was dropped in.
  1184.         if ( flavor.fileType == 'TEXT' )
  1185.             hasValidFile = kODTrue;
  1186.     }
  1187. #endif
  1188.     
  1189.     return hasValidFile;
  1190. }
  1191.  
  1192. //------------------------------------------------------------------------------
  1193. // Method:        CanTranslate                                        [static]
  1194. // Origin:        CCappuccinoContent
  1195. //
  1196. // Description:    This method is called to determine if a storage unit contains
  1197. //                any content that can be translated into a format this part
  1198. //                understands.
  1199. //------------------------------------------------------------------------------
  1200.  
  1201. ODBoolean CCappuccinoContent::CanTranslate( Environment*        ev,
  1202.                                             ODStorageUnit*        su )
  1203. {
  1204.     return GetTranslateKinds(ev, su);
  1205. }
  1206.  
  1207. //------------------------------------------------------------------------------
  1208. // Method:        GetTranslateKinds                                    [static]
  1209. // Origin:        CCappuccinoContent
  1210. //
  1211. // Description:    This method is called to get the first kind of content that a 
  1212. //                storage unit contains that can be translated into a kind this
  1213. //                part supports.  It also returns the kind it can be understood 
  1214. //                as.
  1215. //------------------------------------------------------------------------------
  1216.  
  1217. ODBoolean CCappuccinoContent::GetTranslateKinds( Environment*        ev,
  1218.                                                  ODStorageUnit*        su,
  1219.                                                  ODValueType*        from,
  1220.                                                  ODValueType*        to )
  1221. {
  1222.     ODBoolean found = kODFalse;
  1223.     
  1224.     *from = kODNULL;
  1225.     *to   = kODNULL;
  1226.  
  1227.     // Check for the possibility of translation.
  1228.     ODTranslation* translation = ODGetSession(ev, su)->GetTranslation(ev);
  1229.     
  1230.     // Get the number of values in the contents property.
  1231.     su->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll);
  1232.     ODULong numValues = su->CountValues(ev);
  1233.     
  1234.     // Iterate from 1 to n through the values in the contents property.
  1235.     for ( ODULong index = 1 ; index <= numValues && !found ; index++ )
  1236.     {
  1237.         su->Focus(ev, kODPropContents, kODPosUndefined, 
  1238.                   kODNULL, index, kODPosUndefined);
  1239.         
  1240.         // Get the ISO type name for the value. The temp object
  1241.         // will automatically delete the returned value when this
  1242.         // scope is exited.
  1243.         TempODValueType foreignDataType = su->GetType(ev);
  1244.         
  1245.         // Check that if there is a translator that recognizes the "foreign" data
  1246.         // type, that it can translate to a data type we understand.
  1247.         if ( translation->CanTranslate(ev, foreignDataType) == kODCanTranslate )
  1248.         {
  1249.             TempODTypeList validTypes = translation->GetTranslationOf(ev, foreignDataType);
  1250.             
  1251.             for ( TempODTypeListIterator type(ev, validTypes) ;
  1252.                    type.IsNotComplete() && !found ; type.Next() )
  1253.             {
  1254.                 if ( CCappuccinoContent::IsKindSupported(ev, type) )
  1255.                 {
  1256.                     if ( from != kODNULL )
  1257.                         *from = foreignDataType.DontDelete();
  1258.                     if ( to != kODNULL )
  1259.                         *to   = DuplicateISOStr(type);
  1260.                 
  1261.                     found = kODTrue;
  1262.                     break;
  1263.                 }
  1264.             }
  1265.         }
  1266.     }
  1267.     
  1268.     return found;
  1269. }
  1270.  
  1271. //------------------------------------------------------------------------------
  1272. // Method:        DoSetTextDialog                                        [static]
  1273. // Origin:        CCappuccinoContent
  1274. //
  1275. // Description:    The method is called by the part when the user chooses the
  1276. //                Set Text menu item.
  1277. //------------------------------------------------------------------------------
  1278.  
  1279. void CCappuccinoContent::DoSetTextDialog( Environment*            ev,
  1280.                                           ODFrame*                frame,
  1281.                                           Cappuccino*            part,
  1282.                                           CCappuccinoContent*    currentContent )
  1283. {
  1284. #ifndef qViewerBuild
  1285.     ASSERT_NOT_NULL(frame);
  1286.     ASSERT_NOT_NULL(currentContent);
  1287.     
  1288.     if ( !part->TryToEdit(ev, frame) )
  1289.         return;
  1290.     
  1291.     const ODUShort kTextField = 3;
  1292.     
  1293.     // We must request the Modal focus to prevent multiple modal dialogs being 
  1294.     // displayed simultaneously.
  1295.     
  1296.     TempFocus modalFocus(ev, gGlobals->fModalFocus, frame);
  1297.     if ( modalFocus.Request() )
  1298.     {
  1299.         CTempDialogState dialogState(ev, ODGetSession(ev, part->GetODPart()));
  1300.         DialogPtr dialog = dialogState.CreateDialog(kSetTextDialogID);
  1301.         
  1302.         short    iType;
  1303.         Handle    iHandle;
  1304.         Rect    iRect;
  1305.         
  1306.         // Set dialog font and other std things.
  1307.         SetDialogDefaults(dialog, kDialogFontInfoID, kSettingsFontIndex);
  1308.         
  1309.         // Get a string representation of the font size and put it in the text field.
  1310.         GetDialogItem(dialog, kTextField, &iType, &iHandle, &iRect);
  1311.         SetDialogItemText(iHandle, currentContent->GetString());
  1312.         SelectDialogItemText(dialog, kTextField, 0, 32767);
  1313.         
  1314.         // Show the window and handle events in it.
  1315.         ShowWindow(dialog);
  1316.         
  1317.         ODSShort itemHit;
  1318.         do
  1319.         {
  1320.             ModalDialog(GetODDialogFilter(), &itemHit);
  1321.         }
  1322.         while (itemHit != ok && itemHit != cancel);
  1323.         
  1324.         // If OK was hit, handle the change.
  1325.         if ( itemHit == ok )
  1326.         {
  1327.             // Get the new text.
  1328.             Str255 str;
  1329.             GetDialogItem(dialog, kTextField, &iType, &iHandle, &iRect);
  1330.             GetDialogItemText(iHandle, str);
  1331.             
  1332.             CCappuccinoContent* content = new CCappuccinoContent(part);
  1333.             TempRefCounted contentTemp = content;
  1334.             content->InitCappuccinoContent(ev, str);
  1335.             
  1336.             if ( *currentContent != *content )
  1337.             {
  1338.                 CSetTextAction* action = new CSetTextAction(part, content);
  1339.                 action->Perform(ev);            
  1340.             }
  1341.         }
  1342.     }
  1343. #endif
  1344. }
  1345.  
  1346. //==============================================================================
  1347. #pragma mark    • Operators •
  1348. //==============================================================================
  1349.  
  1350. //------------------------------------------------------------------------------
  1351. // Method:        operator == (CSettings&, CSettings&)
  1352. // Origin:        CSettings
  1353. //------------------------------------------------------------------------------
  1354.  
  1355. ODBoolean operator == (const CCappuccinoContent& a, const CCappuccinoContent& b)
  1356. {
  1357.     return ExactlyEqualStrings(a.fString, b.fString);
  1358. }
  1359.  
  1360. //------------------------------------------------------------------------------
  1361. // Method:        operator != (CSettings&, CSettings&)
  1362. // Origin:        CSettings
  1363. //------------------------------------------------------------------------------
  1364.  
  1365. ODBoolean operator != (const CCappuccinoContent& a, const CCappuccinoContent& b)
  1366. {
  1367.     return !(a == b);
  1368. }
  1369.  
  1370. //==============================================================================
  1371. // CSettings
  1372. //==============================================================================
  1373. #pragma mark    -
  1374.  
  1375. //------------------------------------------------------------------------------
  1376. // Method:        Constructor
  1377. // Origin:        CSettings
  1378. //------------------------------------------------------------------------------
  1379.  
  1380. CSettings::CSettings(Cappuccino* part)
  1381. {
  1382.     fPart        = part;
  1383.     fTextFont    = systemFont;
  1384.     fTextSize    = 0;
  1385.     fDrawFrame    = kODTrue;
  1386. }
  1387.     
  1388. //------------------------------------------------------------------------------
  1389. // Method:        Destructor
  1390. // Origin:        CSettings
  1391. //
  1392. // Notes:        It must be safe to call this routine even if none of the Init
  1393. //                methods have been called (or if the Init methods fail).
  1394. //------------------------------------------------------------------------------
  1395.  
  1396. CSettings::~CSettings()
  1397. {
  1398. }
  1399.  
  1400. //------------------------------------------------------------------------------
  1401. // Method:        UseDefaults
  1402. // Origin:        CSettings
  1403. //------------------------------------------------------------------------------
  1404.  
  1405. void CSettings::UseDefaults()
  1406. {
  1407.     long result = GetScriptVariable(gGlobals->fEditorsScript, 
  1408.                                     smScriptAppFondSize);
  1409.     fTextFont = HiWord(result);
  1410.     fTextSize = LoWord(result);
  1411.  
  1412.     fDrawFrame = kODTrue;
  1413. }
  1414.  
  1415. //==============================================================================
  1416. #pragma mark    • I/O •
  1417. //==============================================================================
  1418.  
  1419. //------------------------------------------------------------------------------
  1420. // Method:        InitSettings
  1421. // Origin:        CSettings
  1422. //------------------------------------------------------------------------------
  1423.  
  1424. void CSettings::InitSettings(Environment* ev)
  1425. {
  1426.     this->UseDefaults();
  1427. }
  1428.  
  1429. //------------------------------------------------------------------------------
  1430. // Method:        InitSettings
  1431. // Origin:        CSettings
  1432. //------------------------------------------------------------------------------
  1433.  
  1434. void CSettings::InitSettings(Environment* ev, ODStorageUnit* su)
  1435. {
  1436.     this->UseDefaults();
  1437.  
  1438.     // Get the size from the font size annotation.
  1439.     if ( su->Exists(ev, kTextSizeAnnotation, kODUShort, 0) )
  1440.         fTextSize = ODGetUShortProp(ev, su, kTextSizeAnnotation, kODUShort);
  1441.     
  1442.     // Get the font from the font size annotation.
  1443.     TempODIText intlFontName = kODNULL;
  1444.     if ( su->Exists(ev, kTextFontAnnotation, kODMacIText, 0) )
  1445.     {
  1446.         intlFontName = ODGetITextProp(ev, su, kTextFontAnnotation, kODMacIText, kODNULL);
  1447.         if ( intlFontName != kODNULL && GetITextStringLength(intlFontName) != 0 )
  1448.         {
  1449.             Str255 fontName;
  1450.             (void) GetITextPString(intlFontName, fontName);
  1451.             GetFNum(fontName, &fTextFont);
  1452.         }
  1453.     }
  1454.     
  1455.     if ( su->Exists(ev, kDrawFrameAnnotation, kODBoolean, 0) )
  1456.         fDrawFrame = ODGetBooleanProp(ev, su, kDrawFrameAnnotation, kODBoolean);
  1457. }
  1458.     
  1459. //------------------------------------------------------------------------------
  1460. // Method:        Externalize
  1461. // Origin:        CSettings
  1462. //------------------------------------------------------------------------------
  1463.  
  1464. void CSettings::Externalize(Environment* ev, ODStorageUnit* su)
  1465. {
  1466.     Str255 fontName;
  1467.     GetFontName(fTextFont, fontName);
  1468.     TempODIText intlFontName = CreateITextPString(smRoman, langEnglish, fontName);
  1469.         
  1470.     ODSetITextProp(ev,   su, kTextFontAnnotation,  kODMacIText, intlFontName);
  1471.     ODSetUShortProp(ev,  su, kTextSizeAnnotation,  kODUShort,   fTextSize);
  1472.     ODSetBooleanProp(ev, su, kDrawFrameAnnotation, kODBoolean,  fDrawFrame);
  1473. }
  1474.  
  1475. //==============================================================================
  1476. #pragma mark    • Settings •
  1477. //==============================================================================
  1478.  
  1479. //------------------------------------------------------------------------------
  1480. // Method:        DoSettingsDialog                                    [static]
  1481. // Origin:        CSettings
  1482. //
  1483. // Description:    The method is called by the part when the user chooses the
  1484. //                Settings menu item or clicks the Settings button in Part Info.
  1485. //------------------------------------------------------------------------------
  1486.  
  1487. void CSettings::DoSettingsDialog( Environment*        ev,
  1488.                                   ODFrame*            frame,
  1489.                                   Cappuccino*        part,
  1490.                                   CSettings*        currentSettings )
  1491. {
  1492. #ifndef qViewerBuild
  1493.     ASSERT_NOT_NULL(currentSettings);
  1494.     ASSERT_NOT_NULL(frame);
  1495.  
  1496.     if ( !part->TryToEdit(ev, frame) )
  1497.         return;
  1498.     
  1499.     const ODUShort kFontPopup = 7;
  1500.     const ODUShort kSizeField = 8;
  1501.     const ODUShort kDrawFrameCheckbox = 9;
  1502.     
  1503.     // We must request the Modal focus to prevent multiple modal dialogs being 
  1504.     // displayed simultaneously.
  1505.     
  1506.     TempFocus modalFocus(ev, gGlobals->fModalFocus, frame);
  1507.     if ( modalFocus.Request() )
  1508.     {
  1509.         CTempDialogState dialogState(ev, ODGetSession(ev, part->GetODPart()));
  1510.         DialogPtr dialog = dialogState.CreateDialog(kSettingsDialogID);
  1511.  
  1512.         short        iType;
  1513.         Handle        iHandle;
  1514.         Rect        iRect;
  1515.         Str255        strValue;
  1516.  
  1517.         // Set dialog font and other std things.
  1518.         SetDialogDefaults(dialog, kDialogFontInfoID, kSettingsFontIndex);
  1519.         
  1520.         // Get a string representation of the font size and put it in the text field.
  1521.         NumToString(currentSettings->fTextSize, strValue);
  1522.         
  1523.         GetDialogItem(dialog, kSizeField, &iType, &iHandle, &iRect);
  1524.         SetDialogItemText(iHandle, strValue);
  1525.         SelectDialogItemText(dialog, kSizeField, 0, 32767);
  1526.         
  1527.         // Get the popup menu control.
  1528.         ControlHandle popupMenu;
  1529.         GetDialogItem(dialog, kFontPopup, &iType, (Handle*) &popupMenu, &iRect);
  1530.         
  1531.         // Find the initial item for the popup menu and set it.
  1532.         {
  1533.             Str255 fontStr;
  1534.             GetFontName(currentSettings->fTextFont, fontStr);
  1535.             
  1536.             PopupPrivateData** privData = (PopupPrivateData**) (**popupMenu).contrlData;
  1537.             MenuHandle privMenu = (**privData).mHandle;
  1538.  
  1539.             short initialItem = 0;
  1540.             for (int i = 1; i <= CountMItems(privMenu); i++)
  1541.             {
  1542.                 Str255 menuItem;
  1543.                 GetMenuItemText(privMenu, i, menuItem);
  1544.                 
  1545.                 if ( IUEqualString(fontStr, menuItem) == 0 )
  1546.                 {
  1547.                     initialItem = i;
  1548.                     break;
  1549.                 }
  1550.             }
  1551.             
  1552.             SetControlValue(popupMenu, initialItem);
  1553.         }
  1554.         
  1555.         // Set initial state of checkboxes.
  1556.         {
  1557.             ControlHandle checkboxH;
  1558.             GetDialogItem(dialog, kDrawFrameCheckbox, &iType, (Handle*) &checkboxH, &iRect);
  1559.             
  1560.             SetControlValue(checkboxH, (short) currentSettings->fDrawFrame);
  1561.         }
  1562.         
  1563.         // Show the window and handle events in it.
  1564.         ShowWindow(dialog);
  1565.         ModalFilterUPP otherDialogProc = NewModalFilterProc(IntegerDialogFilter);
  1566.         
  1567.         ODSShort itemHit;
  1568.         do
  1569.         {
  1570.             ModalDialog(otherDialogProc, &itemHit);
  1571.             
  1572.             GetDialogItem(dialog, itemHit, &iType, &iHandle, &iRect);
  1573.             
  1574.             switch ( itemHit )
  1575.             {
  1576.                 case kDrawFrameCheckbox:
  1577.                     SetControlValue((ControlHandle) iHandle, 
  1578.                                     !GetControlValue((ControlHandle) iHandle));
  1579.                     break;
  1580.             }
  1581.         }
  1582.         while (itemHit != ok && itemHit != cancel);
  1583.  
  1584.         DisposeRoutineDescriptor(otherDialogProc);
  1585.         
  1586.         // If OK was hit, handle the change.
  1587.         if ( itemHit == ok )
  1588.         {
  1589.             CSettings* newSettings = new CSettings(part);
  1590.             TempRefCounted newSettingsTemp = newSettings;
  1591.             
  1592.             // -- Get the font name --
  1593.             short controlValue = GetControlValue(popupMenu);
  1594.             PopupPrivateData** privData = (PopupPrivateData**) (**popupMenu).contrlData;
  1595.             MenuHandle privMenu = (**privData).mHandle;
  1596.             
  1597.             Str255 fontStr;
  1598.             GetMenuItemText(privMenu, controlValue, fontStr);
  1599.             
  1600.             short newFontNum;
  1601.             GetFNum(fontStr, &newFontNum);
  1602.             newSettings->fTextFont = newFontNum;
  1603.             
  1604.             // -- Get the font size --
  1605.             GetDialogItem(dialog, kSizeField, &iType, &iHandle, &iRect);
  1606.             GetDialogItemText(iHandle, strValue);
  1607.             
  1608.             // Get the default size in case the text field is empty.
  1609.             long newSize = LoWord(GetScriptVariable(gGlobals->fEditorsScript, smScriptAppFondSize));    
  1610.             
  1611.             // If the string isn't empty, turn it into a number.
  1612.             if ( strValue[0] > 0 )
  1613.                 StringToNum(strValue, &newSize);
  1614.             
  1615.             // Limit the font size to 512 point (pretty big...).
  1616.             if ( newSize > 512 )
  1617.                 newSize = 512;
  1618.             
  1619.             newSettings->fTextSize = (ODUShort) newSize;
  1620.             
  1621.             // -- Get the 'draw frame' checkbox --
  1622.             {
  1623.                 ControlHandle checkboxH;
  1624.                 GetDialogItem(dialog, kDrawFrameCheckbox, &iType, (Handle*) &checkboxH, &iRect);
  1625.                 
  1626.                 newSettings->fDrawFrame = (ODBoolean) GetControlValue(checkboxH);
  1627.             }
  1628.             
  1629.             // -- Propogate the change --
  1630.             if ( *newSettings != *currentSettings )
  1631.             {
  1632.                 CSettingsChangeAction* action = new CSettingsChangeAction(part, 
  1633.                                                                           newSettings);
  1634.                 action->Perform(ev);
  1635.             }
  1636.         }
  1637.     }
  1638. #endif
  1639. }
  1640.  
  1641. //==============================================================================
  1642. #pragma mark    • Operators •
  1643. //==============================================================================
  1644.  
  1645. //------------------------------------------------------------------------------
  1646. // Method:        operator == (CSettings&, CSettings&)
  1647. // Origin:        CSettings
  1648. //------------------------------------------------------------------------------
  1649.  
  1650. ODBoolean operator == (const CSettings& a, const CSettings& b)
  1651. {
  1652.     return ( a.fTextFont  == b.fTextFont
  1653.           && a.fTextSize  == b.fTextSize
  1654.           && a.fDrawFrame == b.fDrawFrame );
  1655. }
  1656.  
  1657. //------------------------------------------------------------------------------
  1658. // Method:        operator != (CSettings&, CSettings&)
  1659. // Origin:        CSettings
  1660. //------------------------------------------------------------------------------
  1661.  
  1662. ODBoolean operator != (const CSettings& a, const CSettings& b)
  1663. {
  1664.     return !(a == b);
  1665. }
  1666.  
  1667.